package com.uinnova.product.eam.service.cj.service.impl;

import cn.hutool.core.collection.ListUtil;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.model.es.EamAttention;
import com.uinnova.product.eam.feign.workable.entity.TaskResponse;
import com.uinnova.product.eam.model.cj.domain.PlanDesignInstance;
import com.uinnova.product.eam.model.cj.domain.PlanDesignShareRecord;
import com.uinnova.product.eam.model.cj.enums.PlanShareEnum;
import com.uinnova.product.eam.model.cj.enums.PlanSharePermissionEnum;
import com.uinnova.product.eam.model.cj.enums.PlanStatusEnum;
import com.uinnova.product.eam.model.cj.vo.*;
import com.uinnova.product.eam.model.constants.DiagramConstant;
import com.uinnova.product.eam.model.diagram.ESDiagramShareVO;
import com.uinnova.product.eam.model.enums.AssetType;
import com.uinnova.product.eam.service.asset.IAttentionSvc;
import com.uinnova.product.eam.service.cj.dao.PlanDesignInstanceDao;
import com.uinnova.product.eam.service.cj.dao.PlanDesignShareRecordDao;
import com.uinnova.product.eam.service.cj.service.DeliverableTemplateService;
import com.uinnova.product.eam.service.cj.service.FlowableService;
import com.uinnova.product.eam.service.cj.service.ShareService;
import com.uinnova.product.eam.service.exception.BusinessException;
import com.uinnova.project.base.diagram.comm.diagram.ESDiagramShareRecordResult;
import com.uinnova.project.base.diagram.comm.diagram.ShareRecordQueryBean;
import com.uinnova.project.service.eam.ESShareDiagramSvc;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.permission.base.SysOrg;
import com.uino.bean.permission.base.SysUser;
import com.uino.bean.permission.business.UserInfo;
import com.uino.bean.permission.query.CSysUser;
import com.uino.dao.permission.ESUserSvc;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 分享接口实现类
 *
 * @author zhaoxin
 */
@Slf4j
@Service
public class ShareServiceImpl implements ShareService {

    @Resource
    private PlanDesignShareRecordDao planDesignShareRecordDao;
    @Resource
    private PlanDesignInstanceDao planDesignInstanceDao;
    @Resource
    private IUserApiSvc userApiSvc;
    @Resource
    private FlowableService flowableService;
    @Resource
    private DeliverableTemplateService deliverableTemplateService;
    @Resource
    private ESShareDiagramSvc esShareDiagramSvc;

    @Resource
    private IAttentionSvc attentionSvc;

    @Value("${http.resource.space}")
    private String httpPath;

    @Value("${is.gt.environment:false}")
    private Boolean isGtEnvironment;

    @Autowired
    private ESUserSvc userSvc;

    /**
     * 默认的每页个数
     */
    private static final Integer DEFAULT_PAGE_SIZE = 200;
    /**
     * 默认的页码
     */
    private static final Integer DEFAULT_PAGE_NUM = 1;

    /**
     * 查找呗分享列表
     *
     * @param paramMap 参数
     * @return 方案 + 视图集
     */
    @Override
    public List<SharePlanDiagramVO> getSharedList(Map<String, Object> paramMap) {
        List<SharePlanDiagramVO> sharePlanDiagramList = new ArrayList<>();
        Set<Long> attentionIds = queryAttention();
        // 获取方案分享数据
        List<PlanDesignShareRecord> sharedList = getPlanShared(paramMap);
        List<PlanDesignInstance> planList = null;
        if (!CollectionUtils.isEmpty(sharedList)) {
            List<Long> planIdList = sharedList.stream().map(PlanDesignShareRecord::getPlanDesignId).collect(Collectors.toList());
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            queryBuilder.must(QueryBuilders.termsQuery("id", planIdList));
            if(!StringUtils.isEmpty(String.valueOf(paramMap.get("like")))) {
                queryBuilder.must(QueryBuilders.wildcardQuery("name.keyword", "*" + String.valueOf(paramMap.get("like")) + "*"));
            }
            queryBuilder.mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.deleted.name()));
            planList = planDesignInstanceDao.getListByQuery(queryBuilder);
        }

        // 整合方案数据
        if (!CollectionUtils.isEmpty(planList)) {
            Map<Long, PlanDesignShareRecord> planMap = sharedList.stream().collect(Collectors.toMap(PlanDesignShareRecord::getPlanDesignId, item -> item, (k1, k2) -> k1));
            for(PlanDesignInstance planDesignInstance : planList) {
                PlanDesignShareRecord shareRecord = planMap.get(planDesignInstance.getId());
                PlanDesignInstanceResult result = new PlanDesignInstanceResult();
                BeanUtils.copyProperties(planDesignInstance, result);
                result.setPermission(shareRecord.getPermission());
                if (planDesignInstance.isProcessApproval()) {
                    TaskResponse task = flowableService.getCurrentTaskAssignees(String.valueOf(planDesignInstance.getId()));
                    if (task != null) {
                        if (!StringUtils.isEmpty(task.getSubmitter()) && !StringUtils.isEmpty(task.getCurrentAssignees())) {
                            if (!Objects.equals(planDesignInstance.getCreatorCode(), task.getSubmitter()) && task.getCurrentAssignees().contains(planDesignInstance.getCreatorCode())) {
                                result.setStatus(PlanStatusEnum.under_approver.name());
                            } else if (Objects.equals(planDesignInstance.getCreatorCode(), task.getSubmitter()) && task.getCurrentAssignees().contains(planDesignInstance.getCreatorCode())){
                                result.setStatus(PlanStatusEnum.under_submitter.name());
                            } else if (Objects.equals(planDesignInstance.getCreatorCode(), task.getSubmitter()) && !task.getCurrentAssignees().contains(planDesignInstance.getCreatorCode())){
                                result.setStatus(PlanStatusEnum.under_approver.name());
                            }
                        }
                    }
                }
                Long templateId = planDesignInstance.getTemplateId();
                DlvrTemplateVO template = deliverableTemplateService.getDlvrTemplateById(templateId);
                if (template != null && !StringUtils.isEmpty(template.getTemplateName())) {
                    result.setTemplateName(template.getTemplateName());
                }

                SharePlanDiagramVO sharePlanDiagramVO = new SharePlanDiagramVO();
                sharePlanDiagramVO.setPlan(result);
                sharePlanDiagramVO.setAssetType(AssetType.SCHEME);
                sharePlanDiagramVO.setModifyTime(shareRecord.getShareTime());
                if (attentionIds.contains(planDesignInstance.getId())) {
                    sharePlanDiagramVO.setIsAttention(DiagramConstant.IS_ATTENTION);
                }
                // 设置方案状态
                if (!BinaryUtils.isEmpty(planDesignInstance.getStatus())) {
                    if ("draft".equals(planDesignInstance.getStatus())) {
                        if (planDesignInstance.isProcessApproval()) {
                            sharePlanDiagramVO.setReleaseStatus(2);
                        } else {
                            sharePlanDiagramVO.setReleaseStatus(0);
                        }
                    } else if ("approve".equals(planDesignInstance.getStatus())) {
                        sharePlanDiagramVO.setReleaseStatus(2);
                    } else if ("approve_edit".equals(planDesignInstance.getStatus())) {
                        sharePlanDiagramVO.setReleaseStatus(3);
                    } else if ("published".equals(planDesignInstance.getStatus())) {
                        sharePlanDiagramVO.setReleaseStatus(1);
                    }
                }
                sharePlanDiagramList.add(sharePlanDiagramVO);
            }
        }
        // 获取视图被分享数据
        List<ESDiagramShareRecordResult> diagramList = getDiagramShared(paramMap);
        // 整合视图数据
        for(ESDiagramShareRecordResult record : diagramList) {
            if (record.getEsDiagram() != null) {
                SharePlanDiagramVO sharePlanDiagramVO = new SharePlanDiagramVO();
                ESDiagramShareVO shareVO = EamUtil.copy(record.getEsDiagram(), ESDiagramShareVO.class);
                shareVO.setPermission(record.getPermission());
                if(BinaryUtils.isEmpty(shareVO.getReleaseDiagramId())){
                    shareVO.setReleaseStatus(0);
                }else{
                    shareVO.setReleaseStatus(1);
                }
                if (!BinaryUtils.isEmpty(shareVO.getFlowStatus())) {
                    if (!shareVO.getFlowStatus().equals(0)) {
                        shareVO.setReleaseStatus(2);
                    }
                }
                sharePlanDiagramVO.setReleaseStatus(shareVO.getReleaseStatus());
                sharePlanDiagramVO.setDiagram(shareVO);
                sharePlanDiagramVO.setAssetType(AssetType.DIAGRAM);
                sharePlanDiagramVO.setModifyTime(record.getModifyTime());
                if (attentionIds.contains(record.getEsDiagram().getId())) {
                    sharePlanDiagramVO.setIsAttention(DiagramConstant.IS_ATTENTION);
                }
                sharePlanDiagramList.add(sharePlanDiagramVO);
            }
        }
        // 数据排序
        if (!CollectionUtils.isEmpty(sharePlanDiagramList) && sharePlanDiagramList.size() > 1) {
            sharePlanDiagramList.sort((SharePlanDiagramVO o1, SharePlanDiagramVO o2) -> (int) (o2.getModifyTime() - o1.getModifyTime()));
        }
        return sharePlanDiagramList;
    }

    private Set<Long> queryAttention() {
        Set<Long> attentionSet = new HashSet<>();
        List<EamAttention> attentions = attentionSvc.findCurrentUserAttentionList();
        if (!CollectionUtils.isEmpty(attentions)) {
            attentionSet = attentions.stream().map(EamAttention::getAttentionId).collect(Collectors.toSet());
            return attentionSet;
        }
        return Collections.emptySet();
    }

    @Override
    public List<SharedUserVO> findPlanSharedList(Long planDesignId, boolean flag) {
        SysUser user = SysUtil.getCurrentUserInfo();
        if (user == null || StringUtils.isEmpty(user.getLoginCode())) {
            throw new BusinessException("登录已过期，请重新登录!");
        }
        if (planDesignId == null) {
            throw new BusinessException("方案主键不能为空!");
        }
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(planDesignId);
        if (planDesignInstance == null) {
            throw new BusinessException("获取方案信息错误!");
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("planDesignId", planDesignId));
        query.must(QueryBuilders.termQuery("status", PlanShareEnum.SHARING.getStatus()));
        if (flag) {
            List<Integer> permissions = Stream.of(PlanSharePermissionEnum.EDIT_AND_SHARE.getFlag(),
                    PlanSharePermissionEnum.EDIT.getFlag(),
                    PlanSharePermissionEnum.PUBLISH.getFlag()).collect(Collectors.toList());
            query.must(QueryBuilders.termsQuery("permission", permissions));
            query.mustNot(QueryBuilders.termQuery("sharedLoginCode.keyword", user.getLoginCode()));
        }
        List<PlanDesignShareRecord> shareRecordList = planDesignShareRecordDao.getListByQuery(query);
        if (!CollectionUtils.isEmpty(shareRecordList)) {
            List<SharedUserVO> sharedUserList = shareRecordList.stream().map(record -> {
                if (record != null && !StringUtils.isEmpty(record.getSharedLoginCode())) {
                    CSysUser sysUser = new CSysUser();
                    sysUser.setLoginCodeEqual(record.getSharedLoginCode());
                    List<SysUser> sysUserList = userApiSvc.getSysUserByCdt(sysUser);
                    if (!CollectionUtils.isEmpty(sysUserList)) {
                        SysUser sysUserInfo = sysUserList.get(0);
                        SharedUserVO sharedUserVO = new SharedUserVO();
                        sharedUserVO.setLoginCode(sysUserInfo.getLoginCode());
                        sharedUserVO.setUserName(sysUserInfo.getUserName());
                        sharedUserVO.setIcon(sysUserInfo.getIcon());
                        sharedUserVO.setPermission(record.getPermission());
                        return sharedUserVO;
                    }
                }
                return null;
            }).filter(Objects::nonNull).collect(Collectors.toList());

            if (!flag) {
                if (CollectionUtils.isEmpty(sharedUserList)) {
                    sharedUserList = new ArrayList<>();
                }

                UserInfo userInfo = userApiSvc.getUserInfoByLoginCode(planDesignInstance.getCreatorCode());
                SharedUserVO sharedUserVO = new SharedUserVO();
                sharedUserVO.setLoginCode(userInfo.getLoginCode());
                sharedUserVO.setUserName(userInfo.getUserName());
                sharedUserVO.setIcon(userInfo.getIcon());
                sharedUserVO.setPermission(0);
                sharedUserList.add(0, sharedUserVO);
            }
            return sharedUserList;
        } else {
            if (!flag) {
                List<SharedUserVO> sharedUserList = new ArrayList<>();
                UserInfo userInfo = userApiSvc.getUserInfoByLoginCode(planDesignInstance.getCreatorCode());
                SharedUserVO sharedUserVO = new SharedUserVO();
                sharedUserVO.setLoginCode(userInfo.getLoginCode());
                sharedUserVO.setUserName(userInfo.getUserName());
                sharedUserVO.setIcon(userInfo.getIcon());
                sharedUserVO.setPermission(0);
                sharedUserList.add(sharedUserVO);
                return sharedUserList;
            }
        }
        return Collections.emptyList();
    }

    @Override
    public List<PlanDesignShareRecord> getByPlanId(Long planId) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("planDesignId", planId));
        query.must(QueryBuilders.termQuery("status", PlanShareEnum.SHARING.getStatus()));
        List<PlanDesignShareRecord> result = planDesignShareRecordDao.getListByQuery(query);
        return CollectionUtils.isEmpty(result)?Collections.emptyList():result;
    }

    @Override
    public Map<Long, List<PlanDesignShareRecord>> selectByPlanIds(List<Long> planIds) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termsQuery("planDesignId", planIds));
        query.must(QueryBuilders.termQuery("status", PlanShareEnum.SHARING.getStatus()));
        List<PlanDesignShareRecord> result = planDesignShareRecordDao.getListByQuery(query);
        Map<Long, List<PlanDesignShareRecord>> listMap = result.stream().collect(Collectors.groupingBy(PlanDesignShareRecord::getPlanDesignId));
        if (CollectionUtils.isEmpty(listMap)) {
            return Collections.emptyMap();
        }
        return listMap;
    }

    @Override
    public void deleteOrRecoverySharePlan(List<Long> planIds, Integer status) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("planDesignId", planIds));
        List<PlanDesignShareRecord> shareRecordList = planDesignShareRecordDao.getListByQuery(queryBuilder);
        if (!CollectionUtils.isEmpty(shareRecordList)) {
            shareRecordList.forEach(shareRecord -> {
                shareRecord.setStatus(status);
            });
            planDesignShareRecordDao.saveOrUpdateBatch(shareRecordList);
        }
    }

    @Override
    public List<SharedUserVO> findPlanSharedMemberList(Long planDesignId) {
        return findPlanSharedList(planDesignId, true);
    }

    @Override
    public Page<SysUser> findSharedUserList(ShareUserParamVO shareUserParamVO) {
        SysUser sysUserInfo = SysUtil.getCurrentUserInfo();
        if (sysUserInfo == null || StringUtils.isEmpty(sysUserInfo.getLoginCode())) {
            throw new BusinessException("当前用户登录已过期，请重新登录!");
        }
        Page<SysUser> userPage = userApiSvc.findUserInfoByNameForPage(shareUserParamVO.getPageNum(), shareUserParamVO.getPageSize(), shareUserParamVO.getUserName());
        //携带用户所属组织全路径
        addUserOrgName(userPage);
        if (userPage != null && !CollectionUtils.isEmpty(userPage.getData())) {
            userPage.getData().stream().filter(user -> !Objects.equals(user.getLoginCode(), sysUserInfo.getLoginCode()))
                    .map(user -> {
                        if (!StringUtils.isEmpty(user.getIcon()) && !user.getIcon().toLowerCase().startsWith("http://")
                                && !user.getIcon().toLowerCase().startsWith("https://")) {
                            user.setIcon(httpPath + user.getIcon());
                        } else {
                            user.setIcon(user.getIcon());
                        }
                        return user;
                    }).collect(Collectors.toList());
        }
        return userPage;
    }

    private void addUserOrgName(Page<SysUser> userPage) {
        if (isGtEnvironment) {
            return;
        }
        List<SysUser> userInfoList = userPage.getData();
        List<UserInfo> userInfos = userSvc.fillInfo(userInfoList,true);
        Map<Long,String> userOrgMap = new HashMap<>();
        for (UserInfo userInfo : userInfos) {
            Set<SysOrg> orgs = userInfo.getOrgs();
            List<SysOrg> sortOrgList = orgs.stream().sorted(Comparator.comparing(SysOrg::getOrderNo)).collect(Collectors.toList());
            SysOrg sysOrg = sortOrgList.get(0);
            userOrgMap.put(userInfo.getId(),sysOrg.getOrgAllLevelName());
        }
        for (SysUser sysUser : userInfoList) {
            sysUser.setMainOrgAllLevelName(userOrgMap.get(sysUser.getId()));
        }
    }

    @Override
    public List<PlanDesignShareRecord> findPlanShareRecordList(PlanDesignShareRecord planDesignShareRecord) {
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        builder.must(QueryBuilders.termQuery("planDesignId", planDesignShareRecord.getPlanDesignId()));
        builder.must(QueryBuilders.termQuery("sharedLoginCode.keyword", planDesignShareRecord.getSharedLoginCode()));
        builder.must(QueryBuilders.termQuery("status", planDesignShareRecord.getStatus()));
        return planDesignShareRecordDao.getListByQuery(builder);
    }

    /**
     * 获取分享给我的视图
     */
    private List<ESDiagramShareRecordResult> getDiagramShared(Map<String, Object> paramMap) {
        Object queryDiagramObj = paramMap.get("queryDiagram");
        if (!(queryDiagramObj instanceof Boolean) || !((boolean) queryDiagramObj)) {
            return Collections.emptyList();
        }
        String jsonString = JSON.toJSONString(paramMap);
        ShareRecordQueryBean queryBean = JSON.parseObject(jsonString, ShareRecordQueryBean.class);
        if (!StringUtils.isEmpty(queryBean.getOrder()) && !"modifyTime".equals(queryBean.getOrder()) && !"shareTime".equals(queryBean.getOrder())) {
            throw new BusinessException("排序字段不符合规定");
        }
        Page<ESDiagramShareRecordResult> resultPage = esShareDiagramSvc.queryShareRecordPage(queryBean);
        List<ESDiagramShareRecordResult> shareRecordResultList = resultPage.getData();
        return CollectionUtils.isEmpty(resultPage.getData())?Collections.emptyList():resultPage.getData();
    }

    /**
     * 获取分享给我的视图
     */
    private List<PlanDesignShareRecord> getPlanShared(Map<String, Object> paramMap) {
        Object queryPlanObj = paramMap.get("queryPlan");
        if (!(queryPlanObj instanceof Boolean) || !((boolean) queryPlanObj)) {
            return Collections.emptyList();
        }

        int pageNum = Integer.parseInt(Objects.toString(paramMap.get("pageNum"), DEFAULT_PAGE_NUM.toString()));
        int pageSize = Integer.parseInt(Objects.toString(paramMap.get("pageSize"), DEFAULT_PAGE_SIZE.toString()));


        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("sharedLoginCode.keyword", loginCode));
        query.must(QueryBuilders.termQuery("status", PlanShareEnum.SHARING.getStatus()));

        FieldSortBuilder sortBuilder = SortBuilders.fieldSort("modifyTime").order(SortOrder.ASC);

        Page<PlanDesignShareRecord> pageInfo = planDesignShareRecordDao.getSortListByQuery(pageNum, pageSize, query,
                ListUtil.list(false, sortBuilder));

        if (pageInfo.getTotalRows() == 0) {
            return Collections.emptyList();
        } else {
            return pageInfo.getData();
        }
    }

    @Override
    public List<Long> getPublishPermissPlanIds(String sharedLoginCode) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("sharedLoginCode.keyword", sharedLoginCode));
        query.must(QueryBuilders.termQuery("status", PlanShareEnum.SHARING.getStatus()));
        query.must(QueryBuilders.termQuery("permission", PlanSharePermissionEnum.PUBLISH.getFlag()));
        List<PlanDesignShareRecord> shareRecordList = planDesignShareRecordDao.getListByQueryScroll(query);
        return CollectionUtils.isEmpty(shareRecordList) ? new ArrayList<>() :
                shareRecordList.stream().map(PlanDesignShareRecord::getPlanDesignId).distinct().collect(Collectors.toList());
    }
}
